# Copyright (c) 2025 Huawei Technologies Co., Ltd.
# openUBMC is licensed under Mulan PSL v2.
# You can use this software according to the terms and conditions of the Mulan PSL v2.
# You may obtain a copy of Mulan PSL v2 at:
#         http://license.coscl.org.cn/MulanPSL2
# THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
# EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
# MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
# See the Mulan PSL v2 for more details.

# -*- coding: utf-8 -*-
"""
异步异常处理数据流分析测试

测试 try/except 与 Segment/Unit 拆分机制的集成：
- try 块不分割 Segment
- try 块内的 await 分割 Segment
- try 块边界不分割 Unit
- try 块内的变量在 except/finally 中使用时的提升规则
"""

from mcpy.compiler import MCPyCompiler

# 辅助函数定义（用于测试）
HELPER_FUNCTIONS = """
async def async_step1() -> int:
    return 1

async def async_step2() -> int:
    return 2

async def async_step3() -> int:
    return 3

async def async_step(x: int) -> int:
    return x

def may_raise() -> int:
    return 10
"""


def compile_and_get_async_dataflow(source_code: str, add_helpers: bool = True):
    """编译源代码并获取异步数据流分析结果"""
    if add_helpers:
        source_code = HELPER_FUNCTIONS + "\n" + source_code

    compiler = MCPyCompiler()
    result = compiler.compile_source(source_code)
    ir_module = result.ir_module

    if ir_module is None:
        print(f"编译失败！")
        if hasattr(result, "errors") and result.errors:
            print(f"错误信息: {result.errors}")
        raise RuntimeError("编译失败")

    # 收集所有异步函数及其数据流分析结果
    async_functions = {}
    for node in ir_module.walk():
        from mcpy.ir.declarations.function import IRFunctionNode

        if isinstance(node, IRFunctionNode) and node.is_async:
            async_dataflow = node.get_extension_param("async_dataflow")
            if async_dataflow:
                async_functions[node.name] = (node, async_dataflow)

    return ir_module, async_functions


def assert_segment(segment, segment_id, start, end, has_await, try_block_id=None):
    """验证 Segment 的属性"""
    assert segment.segment_id == segment_id
    assert segment.start_stmt_index == start
    assert segment.end_stmt_index == end
    assert segment.has_await == has_await
    if try_block_id is not None:
        assert segment.try_block_id == try_block_id


def assert_unit(unit, unit_id, start, end, has_await, vars_defined, try_block_id=None):
    """验证最小代码单元的属性"""
    assert unit.unit_id == unit_id
    assert unit.start_stmt_index == start
    assert unit.end_stmt_index == end
    assert unit.has_await == has_await
    if try_block_id is not None:
        assert unit.try_block_id == try_block_id

    # 验证变量定义
    for var in vars_defined:
        assert var in unit.variables_defined

    # 验证没有多余的变量（允许外部函数名）
    extra_vars = set(unit.variables_defined) - set(vars_defined)
    if extra_vars:
        external_funcs = {
            v for v in extra_vars if v.startswith("async_") or v.startswith("may_")
        }
        extra_vars -= external_funcs
        assert not extra_vars


def assert_var_promotion(
    async_dataflow, var_name, promotion_type, defined_in_unit=None
):
    """验证变量提升类型"""
    assert var_name in async_dataflow.variable_promotions

    promotion = async_dataflow.variable_promotions[var_name]
    assert promotion.promotion_type == promotion_type

    if defined_in_unit is not None:
        assert promotion.defined_in_unit_id == defined_in_unit

    # 验证变量在相应的列表中
    if promotion_type == "member":
        assert var_name in async_dataflow.member_variables
        assert var_name not in async_dataflow.header_variables
    elif promotion_type == "header":
        assert var_name in async_dataflow.header_variables
        assert var_name not in async_dataflow.member_variables
    elif promotion_type == "local":
        assert var_name not in async_dataflow.member_variables
        assert var_name not in async_dataflow.header_variables


def test_try_block_does_not_split_segment():
    """测试 try 块不分割 Segment

    关键点：
    1. try 块本身不分割 Segment
    2. try 块内的 await 才分割 Segment
    3. Segment 应该按 await 分割，而不是按 try 块分割
    """

    code = """
async def try_with_await() -> int:
    try:
        x = await async_step1()
        y = await async_step2()
    except:
        return 0
    return x + y
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_with_await" in async_funcs

    func_node, async_dataflow = async_funcs["try_with_await"]

    # 验证 Segment 划分
    # try 块不分割 Segment，try 块内的 await 才分割 Segment
    # Segment 0: [0, 1) - x = await async_step1()（在 try 块内）
    # Segment 1: [1, 2) - y = await async_step2()（在 try 块内）
    # Segment 2: [2, 3) - return x + y（try 块外）
    # 注意：try 块本身不创建 Segment，只有 await 才创建 Segment
    assert len(async_dataflow.segments) >= 3

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    # 验证 try 块内的 Segment 记录了 try_block_id
    try_block_id = async_dataflow.try_blocks[0].try_block_id
    segments_in_try = [
        seg for seg in async_dataflow.segments if seg.try_block_id == try_block_id
    ]
    assert len(segments_in_try) >= 2  # 至少有两个 Segment 在 try 块内


def test_try_block_does_not_split_unit():
    """测试 try 块边界不分割 Unit

    关键点：
    1. try 块边界不分割 Unit
    2. Unit 仍然按 await 分割
    3. Unit 记录所属的 try 块信息
    """

    code = """
async def try_with_await() -> int:
    try:
        x = await async_step1()
        y = await async_step2()
    except:
        return 0
    return x + y
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_with_await" in async_funcs

    func_node, async_dataflow = async_funcs["try_with_await"]

    # 验证 Unit 划分
    # try 块边界不分割 Unit，Unit 仍然按 await 分割
    # Unit 0: [0, 1) - x = await async_step1()（在 try 块内）
    # Unit 1: [1, 2) - y = await async_step2()（在 try 块内）
    # Unit 2: [2, 3) - return x + y（try 块外）
    assert len(async_dataflow.units) >= 3

    # 验证 try 块内的 Unit 记录了 try_block_id
    try_block_id = async_dataflow.try_blocks[0].try_block_id
    units_in_try = [
        unit for unit in async_dataflow.units if unit.try_block_id == try_block_id
    ]
    assert len(units_in_try) >= 2  # 至少有两个 Unit 在 try 块内


def test_variable_in_try_used_in_except():
    """测试 try 块内定义的变量在 except 中使用

    关键点：
    1. 变量在 try 块内定义
    2. 变量在 except 中使用
    3. 应该提升为 member 变量
    """

    code = """
async def try_except_var() -> int:
    try:
        x = await async_step1()
        y = await async_step2()
    except:
        return x  # 使用 try 块内定义的 x
    return y
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_except_var" in async_funcs

    func_node, async_dataflow = async_funcs["try_except_var"]

    # 验证变量提升
    # x: 在 try 块内定义，在 except 中使用 → member
    assert_var_promotion(async_dataflow, "x", "member")

    # y: 在 try 块内定义，在 try 块外使用，跨 await → member
    assert_var_promotion(async_dataflow, "y", "member")


def test_variable_in_try_used_in_finally():
    """测试 try 块内定义的变量在 finally 中使用

    关键点：
    1. 变量在 try 块内定义
    2. 变量在 finally 中使用
    3. 应该提升为 member 变量
    """

    code = """
async def try_finally_var() -> int:
    try:
        x = await async_step1()
        y = await async_step2()
    finally:
        return x  # 使用 try 块内定义的 x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_finally_var" in async_funcs

    func_node, async_dataflow = async_funcs["try_finally_var"]

    # 验证变量提升
    # x: 在 try 块内定义，在 finally 中使用 → member
    assert_var_promotion(async_dataflow, "x", "member")

    # y: 在 try 块内定义，但未使用（finally 中只使用了 x）
    # 如果 y 在 try 块外使用，应该是 member；如果只在 try 块内使用，可能是 local
    # 这里假设 y 未在 except/finally 中使用，所以可能不是 member
    # 具体取决于实现细节


def test_nested_try_blocks():
    """测试嵌套 try 块

    关键点：
    1. 嵌套 try 块的处理
    2. 每个 try 块都有独立的 try_block_id
    3. Segment/Unit 记录正确的 try_block_id 和深度
    """

    code = """
async def nested_try() -> int:
    try:
        x = await async_step1()
        try:
            y = await async_step2()
        except:
            return x  # 使用外层 try 块内的 x
        return y
    except:
        return 0
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "nested_try" in async_funcs

    func_node, async_dataflow = async_funcs["nested_try"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) >= 2  # 至少有两个 try 块（外层和内层）

    # 验证嵌套深度
    outer_try = None
    inner_try = None
    for try_block in async_dataflow.try_blocks:
        if try_block.depth == 0:
            outer_try = try_block
        elif try_block.depth == 1:
            inner_try = try_block

    assert outer_try is not None
    assert inner_try is not None
    assert inner_try.parent_try_block_id == outer_try.try_block_id

    # 验证变量提升
    # x: 在外层 try 块内定义，在内层 except 中使用 → member
    assert_var_promotion(async_dataflow, "x", "member")

    # y: 在内层 try 块内定义，在外层 try 块内使用，跨 await → member
    assert_var_promotion(async_dataflow, "y", "member")


def test_try_without_await():
    """测试不包含 await 的 try 块

    关键点：
    1. try 块不包含 await，仍然需要记录 try 块信息
    2. try 块不分割 Segment/Unit
    3. 变量在 except/finally 中使用时的提升规则
    """

    code = """
async def try_no_await() -> int:
    x = await async_step1()
    try:
        y = may_raise()  # 普通函数调用，可能抛出异常
    except:
        return x  # 使用 try 块外的 x
    return y
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_no_await" in async_funcs

    func_node, async_dataflow = async_funcs["try_no_await"]

    # 验证 try 块信息（即使不包含 await，也记录 try 块信息）
    assert len(async_dataflow.try_blocks) > 0

    # 验证 Segment 划分
    # Segment 0: [0, 1) - x = await async_step1()
    # Segment 1: [1, 3) - try 块和 return y（try 块不包含 await，不分割 Segment）
    assert len(async_dataflow.segments) >= 2

    # 验证变量提升
    # x: 在 try 块外定义，在 except 中使用，跨 await → member
    assert_var_promotion(async_dataflow, "x", "member")

    # y: 在 try 块内定义，在 try 块外使用，不跨 await → 可能是 header 或 local
    # 具体取决于实现细节


def test_try_with_multiple_awaits():
    """测试 try 块内包含多个 await

    关键点：
    1. try 块内的每个 await 都分割 Segment
    2. try 块内的每个 await 都分割 Unit
    3. 所有 Segment/Unit 都记录相同的 try_block_id
    """

    code = """
async def try_multiple_awaits() -> int:
    try:
        x = await async_step1()
        y = await async_step2()
        z = await async_step3()
    except:
        return 0
    return x + y + z
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_multiple_awaits" in async_funcs

    func_node, async_dataflow = async_funcs["try_multiple_awaits"]

    # 验证 Segment 划分
    # try 块内的每个 await 都分割 Segment
    # Segment 0: [0, 1) - x = await async_step1()（在 try 块内）
    # Segment 1: [1, 2) - y = await async_step2()（在 try 块内）
    # Segment 2: [2, 3) - z = await async_step3()（在 try 块内）
    # Segment 3: [3, 4) - return x + y + z（try 块外）
    assert len(async_dataflow.segments) >= 4

    # 验证所有 try 块内的 Segment 都有相同的 try_block_id
    try_block_id = async_dataflow.try_blocks[0].try_block_id
    segments_in_try = [
        seg for seg in async_dataflow.segments if seg.try_block_id == try_block_id
    ]
    assert len(segments_in_try) >= 3  # 至少有三个 Segment 在 try 块内

    # 验证 Unit 划分
    assert len(async_dataflow.units) >= 4

    # 验证所有 try 块内的 Unit 都有相同的 try_block_id
    units_in_try = [
        unit for unit in async_dataflow.units if unit.try_block_id == try_block_id
    ]
    assert len(units_in_try) >= 3  # 至少有三个 Unit 在 try 块内

    # 验证变量提升
    # x, y, z: 都在 try 块内定义，在 try 块外使用，跨 await → member
    assert_var_promotion(async_dataflow, "x", "member")
    assert_var_promotion(async_dataflow, "y", "member")
    assert_var_promotion(async_dataflow, "z", "member")


def test_try_except_finally_complex():
    """测试复杂的 try/except/finally 组合

    关键点：
    1. try/except/finally 的组合
    2. 变量在 except 和 finally 中使用
    3. 变量提升规则
    """

    code = """
async def try_except_finally() -> int:
    try:
        x = await async_step1()
        y = await async_step2()
    except:
        return x  # 使用 try 块内的 x
    finally:
        return y  # 使用 try 块内的 y
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_except_finally" in async_funcs

    func_node, async_dataflow = async_funcs["try_except_finally"]

    # 验证变量提升
    # x: 在 try 块内定义，在 except 中使用 → member
    assert_var_promotion(async_dataflow, "x", "member")

    # y: 在 try 块内定义，在 finally 中使用 → member
    assert_var_promotion(async_dataflow, "y", "member")


def test_try_with_control_flow():
    """测试 try 块内包含控制流语句

    关键点：
    1. try 块内可以包含 if/for/while 等控制流语句
    2. 控制流语句的处理不受 try 块影响
    3. Segment/Unit 的划分仍然正确
    """

    code = """
async def try_with_if() -> int:
    try:
        x = await async_step1()
        if x > 0:
            y = await async_step2()
        else:
            y = 0
        return y
    except:
        return x  # 使用 try 块内的 x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_with_if" in async_funcs

    func_node, async_dataflow = async_funcs["try_with_if"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    # 验证 Segment 划分
    # try 块内的 await 分割 Segment，if 语句也分割 Segment（如果包含 await）
    assert len(async_dataflow.segments) >= 3

    # 验证变量提升
    # x: 在 try 块内定义，在 except 中使用 → member
    assert_var_promotion(async_dataflow, "x", "member")

    # y: 在 try 块内定义，在 try 块内使用，跨 await → member
    assert_var_promotion(async_dataflow, "y", "member")


def test_try_except_with_local_var():
    """测试 try 块内定义的变量只在 try 块内使用

    关键点：
    1. 变量在 try 块内定义和使用
    2. 不在 except/finally 中使用
    3. 应该按照正常的变量提升规则处理
    """

    code = """
async def try_local_var() -> int:
    try:
        x = await async_step1()
        y = x + 10  # 在 try 块内使用 x
        return y
    except:
        return 0
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_local_var" in async_funcs

    func_node, async_dataflow = async_funcs["try_local_var"]

    # 验证变量提升
    # x: 在 try 块内定义，在 try 块内使用，不跨 await（y = x + 10 在同一个 Unit）→ local
    # 或者如果 y = x + 10 在下一个 Unit，则跨 await → member
    # 具体取决于 Unit 划分

    # y: 在 try 块内定义和使用，不跨 await → local
    # 或者如果 return y 在下一个 Unit，则跨 await → member
    # 具体取决于 Unit 划分


def test_nested_try_blocks_parent_relationship():
    """测试嵌套 try 块的父子关系

    关键点：
    1. 验证 parent_try_block_id 正确记录
    2. 验证三层嵌套 try 块的关系
    """

    code = """
async def triple_nested_try() -> int:
    try:  # try_block_id = 0
        x = await async_step1()
        try:  # try_block_id = 1, parent = 0
            y = await async_step2()
            try:  # try_block_id = 2, parent = 1
                z = await async_step3()
            except:
                return y
        except:
            return x
        return z
    except:
        return 0
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "triple_nested_try" in async_funcs

    func_node, async_dataflow = async_funcs["triple_nested_try"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) >= 3  # 至少有三个 try 块

    # 验证嵌套深度和父子关系
    try_blocks_by_depth = {}
    for try_block in async_dataflow.try_blocks:
        try_blocks_by_depth[try_block.depth] = try_block

    assert 0 in try_blocks_by_depth  # 外层 try
    assert 1 in try_blocks_by_depth  # 中层 try
    assert 2 in try_blocks_by_depth  # 内层 try

    outer_try = try_blocks_by_depth[0]
    middle_try = try_blocks_by_depth[1]
    inner_try = try_blocks_by_depth[2]

    # 验证父子关系
    assert middle_try.parent_try_block_id == outer_try.try_block_id
    assert inner_try.parent_try_block_id == middle_try.try_block_id

    # 验证 Segment 的 parent_try_block_id
    segments_by_try = {}
    for seg in async_dataflow.segments:
        if seg.try_block_id is not None:
            if seg.try_block_id not in segments_by_try:
                segments_by_try[seg.try_block_id] = []
            segments_by_try[seg.try_block_id].append(seg)

    # 验证内层 try 的 Segment 有正确的 parent_try_block_id
    if inner_try.try_block_id in segments_by_try:
        for seg in segments_by_try[inner_try.try_block_id]:
            assert seg.parent_try_block_id == middle_try.try_block_id

    # 验证中层 try 的 Segment 有正确的 parent_try_block_id
    if middle_try.try_block_id in segments_by_try:
        for seg in segments_by_try[middle_try.try_block_id]:
            assert seg.parent_try_block_id == outer_try.try_block_id


def test_try_block_has_finally_and_else():
    """测试 try 块的 has_finally 和 has_else 字段

    关键点：
    1. 验证 TryBlockInfo 正确记录 has_finally
    2. 验证 TryBlockInfo 正确记录 has_else
    """

    code = """
async def try_with_finally_and_else() -> int:
    try:
        x = await async_step1()
    except:
        return 0
    else:
        return x
    finally:
        pass
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_with_finally_and_else" in async_funcs

    func_node, async_dataflow = async_funcs["try_with_finally_and_else"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    try_block = async_dataflow.try_blocks[0]
    assert try_block.has_finally is True
    assert try_block.has_else is True


def test_try_block_without_finally_and_else():
    """测试没有 finally 和 else 的 try 块

    关键点：
    1. 验证 has_finally 和 has_else 为 False
    """

    code = """
async def try_without_finally_and_else() -> int:
    try:
        x = await async_step1()
    except:
        return 0
    return x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_without_finally_and_else" in async_funcs

    func_node, async_dataflow = async_funcs["try_without_finally_and_else"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    try_block = async_dataflow.try_blocks[0]
    assert try_block.has_finally is False
    assert try_block.has_else is False


def test_try_block_has_except_handlers():
    """测试 try 块的 has_except_handlers 字段

    关键点：
    1. 验证 TryBlockInfo 正确记录 has_except_handlers
    """

    code = """
async def try_with_except() -> int:
    try:
        x = await async_step1()
    except ValueError:
        return 0
    return x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_with_except" in async_funcs

    func_node, async_dataflow = async_funcs["try_with_except"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    try_block = async_dataflow.try_blocks[0]
    assert try_block.has_except_handlers is True


def test_try_block_in_loop():
    """测试 try 块在循环中的情况

    关键点：
    1. 验证 TryBlockInfo 正确记录 in_loop
    2. 验证 TryBlockInfo 正确记录 loop_type
    """

    code_for = """
async def try_in_for_loop() -> int:
    for i in range(3):
        try:
            x = await async_step1()
        except:
            return 0
    return x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code_for)
    assert "try_in_for_loop" in async_funcs

    func_node, async_dataflow = async_funcs["try_in_for_loop"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    try_block = async_dataflow.try_blocks[0]
    assert try_block.in_loop is True
    assert try_block.loop_type == "for"

    code_while = """
async def try_in_while_loop() -> int:
    cond = await async_step1()
    while cond:
        try:
            x = await async_step2()
        except:
            return 0
        cond = await async_step3()
    return x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code_while)
    assert "try_in_while_loop" in async_funcs

    func_node, async_dataflow = async_funcs["try_in_while_loop"]

    # 验证 try 块信息（应该有 while 循环中的 try 块）
    try_blocks_in_loop = [tb for tb in async_dataflow.try_blocks if tb.in_loop]
    assert len(try_blocks_in_loop) > 0

    try_block = try_blocks_in_loop[0]
    assert try_block.in_loop is True
    assert try_block.loop_type == "while"


def test_try_block_not_in_loop():
    """测试 try 块不在循环中的情况

    关键点：
    1. 验证 in_loop 为 False
    2. 验证 loop_type 为 None
    """

    code = """
async def try_not_in_loop() -> int:
    try:
        x = await async_step1()
    except:
        return 0
    return x
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code)
    assert "try_not_in_loop" in async_funcs

    func_node, async_dataflow = async_funcs["try_not_in_loop"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) > 0

    try_block = async_dataflow.try_blocks[0]
    assert try_block.in_loop is False
    assert try_block.loop_type is None


def test_else_raise_with_finally_try_block_info():
    """测试 else raise with finally 的 try 块信息

    关键点：
    1. 验证嵌套 try 块的信息收集
    2. 验证外层 try 块的 has_except_handlers
    3. 验证内层 try 块的 has_else 和 has_finally
    """

    code = """
async def test_else_raise_with_finally():
    async def async_func() -> int:
        return 42

    global finally_executed
    finally_executed = False
    exception_caught = False

    try:
        try:
            result = await async_func()
        except ValueError:
            pass
        else:
            raise RuntimeError("from else")
        finally:
            finally_executed = True
    except RuntimeError:
        exception_caught = True
"""

    ir_module, async_funcs = compile_and_get_async_dataflow(code, add_helpers=False)
    assert "test_else_raise_with_finally" in async_funcs

    func_node, async_dataflow = async_funcs["test_else_raise_with_finally"]

    # 验证 try 块信息
    assert len(async_dataflow.try_blocks) >= 2  # 外层和内层 try 块

    # 查找外层和内层 try 块
    outer_try = None
    inner_try = None
    for try_block in async_dataflow.try_blocks:
        if try_block.depth == 0:
            outer_try = try_block
        elif try_block.depth == 1:
            inner_try = try_block

    assert outer_try is not None
    assert inner_try is not None

    # 验证外层 try 块
    print(
        f"外层 try 块: has_except_handlers={outer_try.has_except_handlers}, has_else={outer_try.has_else}, has_finally={outer_try.has_finally}"
    )
    assert outer_try.has_except_handlers is True  # 有 except RuntimeError
    assert outer_try.has_else is False
    assert outer_try.has_finally is False

    # 验证内层 try 块
    print(
        f"内层 try 块: has_except_handlers={inner_try.has_except_handlers}, has_else={inner_try.has_else}, has_finally={inner_try.has_finally}"
    )
    assert inner_try.has_except_handlers is True  # 有 except ValueError
    assert inner_try.has_else is True  # 有 else 块
    assert inner_try.has_finally is True  # 有 finally 块

    # 验证嵌套关系
    assert inner_try.parent_try_block_id == outer_try.try_block_id
